/**
 * 给定一个 完美二叉树 ，其所有叶子节点都在同一层，每个父节点都有两个子节点。
 * 填充它的每个 next 指针，让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点，则将 next 指针设置为 NULL。
 * 初始状态下，所有 next 指针都被设置为 NULL。
 * 输入：root = [1,2,3,4,5,6,7]
 * 输出：[1,#,2,3,#,4,5,6,7,#]
 * 解释：给定二叉树如图 A 所示，你的函数应该填充它的每个 next 指针，以指向其下一个右侧节点，如图 B 所示。序列化的输出按层序遍历排列，同一层节点由 next 指针连接，'#' 标志着每一层的结束。
 */

#include<stack>
#include<queue>
using namespace std;

class Node {
public:
    int val;
    Node* left;
    Node* right;
    Node* next;

    Node() : val(0), left(NULL), right(NULL), next(NULL) {}

    Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}

    Node(int _val, Node* _left, Node* _right, Node* _next)
        : val(_val), left(_left), right(_right), next(_next) {}
};

/**
 * Solution 1:层次遍历
 * 层次遍历基于广度优先搜索，它与广度优先搜索的不同之处在于，广度优先搜索每次只会取出一个节点来拓展，而层次遍历会每次将队列中的所有元素都拿出来拓展，这样能保证每次从队列中拿出来遍历的元素都是属于同一层的
 * 因此我们可以在遍历的过程中修改每个节点的 \text{next}next 指针，同时拓展下一层的新队列。
 */
class Solution {
public:
    Node* connect(Node* root) {
        if(root == NULL){
            return NULL;
        }

        queue<Node*> q;
        q.push(root);

        while (!q.empty()){
            // 确定每一层节点个数，对每一层节点进行连接
            int size = q.size();

            for(int i=0; i<size; i++){
                // 取出队首节点
                Node* n = q.front();
                q.pop();

                // 这里只能用if不能用while，因为在这个小循环里没有对计数变量进行处理，用while因为i没有改变，会陷入死循环
                if (i < size-1){
                    // 非最右节点依此连起来，最右节点的next指针在初始化时就是NULL，不用再处理
                    n->next = q.front();
                }

                // 把当前节点的左右孩子加入队列
                if(n->left != NULL){
                    q.push(n->left);
                }
                if(n->right != NULL){
                    q.push(n->right);
                }                
            }
        }
        return root;
        
    }
};

/**
 * Solution 2:递归，比层次遍历有更小的时间空间复杂度
 * 关键是利用题目提供的满二叉树条件
 * 注意：初始时node->next都设为 NULL
 */
class Solution_1 {
public:
    Node* connect(Node* root) {
        if(root == NULL){
            return NULL;
        }

        // 此条件等同于下一层还有节点
        if(root->left != NULL){
            root->left->next = root->right;
            // 此条件说明root同层还有兄弟节点，root->right的next是兄弟节点的left
            if(root->next != NULL){
                root->right->next = root->next->left;
            }         
        }
        // 处理完根节点，再处理其子节点
        connect(root->left);
        connect(root->right);   
        return root;
    }
};
